package com.lboyang.core.spring;


import com.lboyang.common.extension.ExtensionLoader;
import com.lboyang.common.factory.SingletonFactory;
import com.lboyang.core.annotation.NnziReference;
import com.lboyang.core.annotation.NnziService;
import com.lboyang.core.proxy.RpcClientProxy;
import com.lboyang.provider.config.RpcServiceConfig;
import com.lboyang.provider.service.ServiceProvider;
import com.lboyang.provider.service.zkImpl.ZkServiceProviderImpl;
import com.lboyang.remoting.transport.NrpcRequestTransport;
import com.lboyang.remoting.transport.netty.server.NettyRpcServer;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

/**
 * call this method before creating the bean to see if the class is annotated
 *
 * @author shuang.kou
 * @createTime 2020年07月14日 16:42:00
 */
@Slf4j
@Component
public class SpringBeanPostProcessor implements BeanPostProcessor {


    /**
     * RPC 框架的网络传输客户端
     */
    private final NrpcRequestTransport rpcClient;

    /**
     * 获取容器中的 Netty 服务器端
     */
    @Autowired
    private NettyRpcServer nettyRpcServer;

    public SpringBeanPostProcessor() {
        this.rpcClient = ExtensionLoader.getExtensionLoader(NrpcRequestTransport.class).getExtension("netty");
    }

    /**
     * bean 初始化前的后置处理器
     * 将标有 @NnziService 注解的类，在初始化前先暴露服务
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @SneakyThrows
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        // 通过反射获取 NnziService 注解（如果有）
        if (bean.getClass().isAnnotationPresent(NnziService.class)) {
            log.info("[{}] is annotated with  [{}]", bean.getClass().getName(), NnziService.class.getCanonicalName());
            NnziService rpcService = bean.getClass().getAnnotation(NnziService.class);
            // 构建一个 RPC 服务的对象
            RpcServiceConfig rpcServiceConfig = RpcServiceConfig.builder()
                    .group(rpcService.group())
                    .version(rpcService.version())
                    .service(bean).build();
            // 向注册中心注册
            nettyRpcServer.registerService(rpcServiceConfig);

            // 如果没有启动对应 Netty 服务端的话则启动
            nettyRpcServer.start();

        }
        return bean;
    }

    /**
     * bean初始化后的后置处理器
     * 将标注 @NnziReference 注解的类生成代理对象并注入
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> targetClass = bean.getClass();
        Field[] declaredFields = targetClass.getDeclaredFields();
        // 遍历所有字段
        for (Field declaredField : declaredFields) {
            NnziReference rpcReference = declaredField.getAnnotation(NnziReference.class);
            // 如果有 @NnziReference 注解
            if (rpcReference != null) {
                RpcServiceConfig rpcServiceConfig = RpcServiceConfig.builder()
                        .group(rpcReference.group())
                        .version(rpcReference.version()).build();
                // 生成对应的代理对象，开启 Netty 客户端并且订阅对应的服务
                RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcClient, rpcServiceConfig);
                Object clientProxy = rpcClientProxy.getProxy(declaredField.getType());
                declaredField.setAccessible(true);
                try {
                    // 自动注入
                    declaredField.set(bean, clientProxy);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }
        return bean;
    }
}
